/** Fichier implémentant un hyperboloïde.
 *
 * Ce fichier contient l'implémentation de la classe Hyperboloide.
 *
 * @file Hyperboloide.cpp
 * @author Johan "Solo" Luisier
 * @date 3 Juillet 2011
 */
#include "Hyperboloide.hpp"

#include "BaseHyperboloide.hpp"
#include "Plan.hpp"

#include "Utils/ATL.hpp"

using namespace std;

/** Constructeur par défaut.
 *
 * Ce constructeur initialise un hyperboloïde centré sur l'origine, avec une
 * transformation identité. L'hyperboloïde créé a une hauteur de 10, et sa
 * "base" est une ellipse dont les rayons sont 1 et 2.
 */
Hyperboloide::Hyperboloide()
{
    Coord pt( 0., 0., 0. );
    Vecteur axeX( 1., 0., 0.);
    Vecteur axeY( 0., 1., 0.);
    Vecteur axeZ( 0., 0., 1.);

    BHyperbole = BaseHyperboloide::SharedPtr( new BaseHyperboloide( pt, axeX, axeY, axeZ,
                                                                    1., 2., 1. ) );

    ListePlan.push_back( Plan::SharedPtr( new Plan( -axeZ, pt - 5. * axeZ ) ) );
    ListePlan.push_back( Plan::SharedPtr( new Plan( axeZ, pt + 5. * axeZ ) ) );

    form[ 0 ] = new FormeComposee( inter, BHyperbole.get(), ListePlan[0].get() );
    form[ 1 ] = ListePlan[1].get();

    PseudoCentre = pt;
    PseudoRayon = sqrt( puissance< 2u >( 10. ) + puissance< 2u > ( 5. ) );

    op = inter;

    Nom = "Hyperboloïde";
}

/** Constructeur standard, permettant d'initialiser toutes les variables.
 *
 * @param[in] sommet "centre" de l'hyperboloïde, càd le centre de
 * l'ellipse de la "base".
 * @param[in] axeX axe x des coordonées locales.
 * @param[in] axeY axe y des coordonées locales.
 * @param[in] axeZ axe z des coordonées locales.
 * @param[in] echelleX facteur d'échelle selon l'axe x local.
 * @param[in] echelleY facteur d'échelle selon l'axe y local.
 * @param[in] echelleZ facteur d'échelle selon l'axe z local.
 * @param[in] hauteurPlus hauteur de l'hyperboloïde dans le sens positif
 * de l'axe z local.
 * @param[in] hauteurMoins hauteur de l'hyperboloïde dans le sens négatif
 * de l'axe z local.
 */
Hyperboloide::Hyperboloide( const Coord& sommet,
                            const Vecteur& axeX, const Vecteur& axeY,
                            const Vecteur& axeZ,
                            const double& echelleX, const double& echelleY,
                            const double& echelleZ,
                            const double& hauteurPlus,
                            const double& hauteurMoins )
{
    BHyperbole = BaseHyperboloide::SharedPtr( new BaseHyperboloide( sommet, axeX, axeY, axeZ,
                                                                    echelleX, echelleY, echelleZ ) );

    Coord pt( sommet );
    pt += hauteurMoins * (-axeZ);

    ListePlan.push_back( Plan::SharedPtr( new Plan( -axeZ, pt ) ) );

    pt = sommet;
    pt += hauteurPlus * axeZ;

    ListePlan.push_back( Plan::SharedPtr( new Plan( axeZ, pt ) ) );

    form[ 0 ] = new FormeComposee( inter, BHyperbole.get(), ListePlan[0].get() );
    form[ 1 ] = ListePlan[1].get();

    double x( ( 1. + puissance< 2u > ( max( echelleX, echelleY ) / echelleZ ) ) * ( hauteurMoins - hauteurPlus ) / 2. );

    PseudoCentre = sommet + axeZ * x;
    PseudoRayon = 1.8 * sqrt( puissance< 2u >( hauteurPlus + x ) +
                              puissance< 2u >( max( echelleX, echelleY ) / echelleZ *
                                               hauteurPlus ) );

    op = inter;

    Nom = "Hyperboloïde";
}

// Hyperboloide::Hyperboloide( const Hyperboloide& par )
//   : Forme( par ), Sommet( par.sommet() ),
//     AxeX( par.axeX() ), AxeY( par.axeY() ), AxeZ( par.axeZ() ),
//     EchelleX( par.echelleX() ), EchelleY( par.echelleY() ),
//     EchelleZ( par.echelleZ() ), HauteurPlus( par.hauteurPlus() ),
//     HauteurMoins( par.hauteurMoins() )
// {
//   BasePlus  = Plan( Sommet + HauteurPlus * AxeZ, AxeZ );
//   BaseMoins = Plan( Sommet - HauteurMoins * AxeZ, - AxeZ );

//   ReduitCoordonnes = MatriceGL3( 1. / EchelleX, 1. / EchelleY, 1. / EchelleZ );

//   m_solveur = new Solveur();
// }

/** Destructeur, virtuel pour assurer une séquence de destruction correcte.
 *
 * Le destructeur doit libérer la mémoire allouée pour la forme composée.
 */
Hyperboloide::~Hyperboloide()
{
    delete form[ 0 ];
    form[ 0 ] = 0;
}
